package org.budo.redis.jdbc.driver.parser.impl;

import java.util.ArrayList;
import java.util.List;

import org.budo.jdbc.driver.exception.BudoJdbcDriverNotSupportedException;
import org.budo.jdbc.driver.statement.impl.SELECT_AT_AT;
import org.budo.jdbc.driver.statement.impl.SELECT_INFORMATION_SCHEMA;
import org.budo.jdbc.driver.statement.impl.SET_NAMES;
import org.budo.jdbc.driver.statement.impl.SHOW_CHARACTER_SET;
import org.budo.jdbc.driver.statement.impl.SHOW_COLUMNS;
import org.budo.jdbc.driver.statement.impl.SHOW_CREATE_TABLE;
import org.budo.jdbc.driver.statement.impl.SHOW_ENGINES;
import org.budo.jdbc.driver.statement.impl.SHOW_PROCEDURE_STATUS;
import org.budo.jdbc.driver.statement.impl.SHOW_STATUS;
import org.budo.jdbc.driver.statement.impl.SHOW_VARIABLES;
import org.budo.redis.jdbc.driver.statement.hash.HDEL;
import org.budo.redis.jdbc.driver.statement.hash.HGET;
import org.budo.redis.jdbc.driver.statement.key.DEL;
import org.budo.redis.jdbc.driver.statement.key.EXPIRE;
import org.budo.redis.jdbc.driver.statement.key.KEYS;
import org.budo.redis.jdbc.driver.statement.mysql.CREATE_TABLE;
import org.budo.redis.jdbc.driver.statement.mysql.DROP_TABLE;
import org.budo.redis.jdbc.driver.statement.mysql.SELECT_HELP;
import org.budo.redis.jdbc.driver.statement.mysql.SELECT_MYSQL;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_COLLATION;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_CREATE_FUNCTION;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_DATABASES;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_FULL_COLUMNS;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_FULL_TABLES;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_FUNCTION_STATUS;
import org.budo.redis.jdbc.driver.statement.mysql.SHOW_TABLE_STATUS;
import org.budo.redis.jdbc.driver.statement.string.GET;
import org.budo.redis.jdbc.driver.statement.string.SET;

/**
 * @author lmw
 */
public class ParseUtil implements ParseConstants {
    private static final String[] NO_PARAMETER_FUNCTIONS = { SHOW_STATUS_2, SHOW_COLLATION_2, SHOW_CHARACTER_SET_2, SHOW_VARIABLES_2, SHOW_DATABASES_2, SHOW_ENGINES_2, //
            SHOW_COLUMNS_FROM_2, SHOW_FULL_COLUMNS_FROM_2, SHOW_FULL_TABLES_2, //
            SHOW_PROCEDURE_STATUS_2, SHOW_TABLE_STATUS_2, SHOW_FUNCTION_STATUS_2, //
            SHOW_CREATE_TABLE_2, SHOW_CREATE_FUNCTION_2, //
            SELECT_AT_AT_2, SELECT_FROM_MYSQL, //
            SET_NAMES_2, CREATE_TABLE_2, DROP_TABLE_2 };

    private static final String[] JUST_RETURN_FUNCTION_SQL = { SHOW_STATUS_1, SHOW_ENGINES_1, SHOW_COLLATION_1, SHOW_CHARACTER_SET_1, SHOW_VARIABLES_1, SHOW_DATABASES_1, //
            SHOW_COLUMNS_FROM_1, SHOW_FULL_COLUMNS_FROM_1, SHOW_FULL_TABLES_1, //
            SHOW_TABLE_STATUS_1, SHOW_FUNCTION_STATUS_1, SHOW_PROCEDURE_STATUS_1, //
            SHOW_CREATE_TABLE_1, SHOW_CREATE_FUNCTION_1, //
            SELECT_AT_AT_1, //
            SET_NAMES_1, CREATE_TABLE_1, DROP_TABLE_1, };

    static String functionSql(String sql) {
        String sqlTrim = sql.replaceAll(BLANK_REGEX, " ") // 清除换行
                .replaceAll(" +", " ") // 多个空格变一个空格
                .trim();

        String sqlUpper = sqlTrim.toUpperCase();

        for (String each : JUST_RETURN_FUNCTION_SQL) {
            if (sqlUpper.startsWith(each)) {
                return sqlUpper.trim();
            }
        }

        // select from information_schema
        if (sqlUpper.startsWith(SELECT) && sqlUpper.contains(FROM_INFORMATION_SCHEMA_1)) {
            return sqlUpper.trim();
        }

        // select function
        int selectIndex = sqlUpper.indexOf(SELECT); // SELECT KEYS('*abc*')
        if (selectIndex > -1) {
            String functionSql = sql.substring(selectIndex + SELECT.length());
            return functionSql.trim();
        }

        // where function
        int whereIndex = sqlUpper.indexOf(WHERE); // DELETE FROM session WHERE DEL(?)
        if (whereIndex > 0) {
            String functionSql = sql.substring(whereIndex + WHERE.length());
            return functionSql.trim();
        }

        throw new BudoJdbcDriverNotSupportedException("#54 sql error, sql=" + sql);
    }

    /**
     * 解析无function的特定语句
     */
    static String[] parseFunctionParameters_2(String sql) {
        String sqlTrim = sql.replaceAll(BLANK_REGEX, "").replaceAll(" +", "").trim();
        String sqlTrimUpper = sqlTrim.toUpperCase();

        if (sqlTrimUpper.contains(SET_VALUE) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是update-value特例语句
            int a = sqlTrimUpper.indexOf(SET_VALUE);
            int b = sqlTrimUpper.indexOf(WHERE, a + SET_VALUE.length());

            String value = sqlTrim.substring(a + SET_VALUE.length(), b);
            String valueParameter = parseParameter(value);

            int c = sqlTrimUpper.indexOf(WHERE_KEY_EQ);

            String key = sqlTrim.substring(c + WHERE_KEY_EQ.length());
            String keyParameter = parseParameter(key);

            if (keyParameter.equals("?") && valueParameter.equals("?")) {
                return new String[] { "?2", "?1" };
            }
            return new String[] { keyParameter, valueParameter };
        }

        // 是update-expire特例语句
        if (sqlTrimUpper.contains(SET_EXPIRE) && sqlTrimUpper.contains(WHERE_KEY_EQ)) {
            int a = sqlTrimUpper.indexOf(SET_EXPIRE);
            int b = sqlTrimUpper.indexOf(WHERE, a + SET_EXPIRE.length());

            String expire = sqlTrim.substring(a + SET_EXPIRE.length(), b);
            String expireParameter = parseParameter(expire);

            int c = sqlTrimUpper.indexOf(WHERE_KEY_EQ);

            String key = sqlTrim.substring(c + WHERE_KEY_EQ.length());
            String keyParameter = parseParameter(key);

            if (keyParameter.equals("?") && expireParameter.equals("?")) {
                return new String[] { "?2", "?1" };
            }

            return new String[] { keyParameter, expireParameter };
        }

        // UPDATE hash.session SET
        // UPDATEHASH.SESSIONSETFIELD_1=NULL,FIELD_2=NULLWHEREKEY=?
        if (sqlTrimUpper.startsWith(UPDATE_HASH) && sqlTrimUpper.contains(SET) && sqlTrimUpper.contains(EQ_NULL) && sqlTrimUpper.contains(WHERE_KEY_EQ)) {
            List<String> params = new ArrayList<String>();

            int c = sqlTrimUpper.indexOf(WHERE_KEY_EQ);
            String key = sqlTrim.substring(c + WHERE_KEY_EQ.length());

            params.add(parseParameter(key)); // 可能是问号

            int fromIndex = 0;
            while (true) {
                int a = sqlTrimUpper.indexOf(SET, fromIndex);
                if (a < 0) {
                    a = sqlTrimUpper.indexOf(',', fromIndex);
                    if (a < 0) {
                        break;
                    }
                    a = a - 2; // 如果是逗号，从逗号后截取，长度与SET不同
                }

                a += SET.length(); // 从SET后面截取

                int b = sqlTrimUpper.indexOf(EQ_NULL, a);
                String field = sqlTrim.substring(a, b);
                params.add(field); // 不可能是问号
                fromIndex = b;
            }

            return params.toArray(new String[params.size()]);
        }

        // SELECT field_1 FROM hash.session WHERE key=?
        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_HASH) && sqlTrimUpper.contains(WHERE_KEY_EQ)) {
            int b = sqlTrimUpper.indexOf(FROM_HASH);
            String field = sqlTrim.substring(SELECT.length(), b);

            int c = sqlTrimUpper.indexOf(WHERE_KEY_EQ);
            String key = sqlTrim.substring(c + WHERE_KEY_EQ.length());
            return new String[] { parseParameter(key), field };
        }

        if (sqlTrimUpper.startsWith(SELECT_VALUE_FROM) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是select-value特例语句
            int a = sqlTrimUpper.indexOf(WHERE_KEY_EQ);
            String selectKey = sqlTrim.substring(a + WHERE_KEY_EQ.length());
            String selectKeyParameter = parseParameter(selectKey); // 去掉引号
            return new String[] { selectKeyParameter };
        }

        if (sqlTrimUpper.startsWith(SELECT_KEY_FROM) && sqlTrimUpper.contains(WHERE_KEY_LIKE)) { // 是select-key特例语句
            int a = sqlTrimUpper.indexOf(WHERE_KEY_LIKE);
            String selectKey = sqlTrim.substring(a + WHERE_KEY_LIKE.length());
            String selectKeyParameter = parseParameter(selectKey); // 去掉引号
            return new String[] { selectKeyParameter };
        }

        if (sqlTrimUpper.startsWith(DELETE_FROM) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是delete-key特例语句
            int a = sqlTrimUpper.indexOf(WHERE_KEY_EQ);
            String delKey = sqlTrim.substring(a + WHERE_KEY_EQ.length());
            String delKeyParameter = parseParameter(delKey); // 去掉引号
            return new String[] { delKeyParameter };
        }

        if (sqlTrimUpper.startsWith(SELECT_FROM_HELP_1) || sqlTrimUpper.startsWith(SELECT_FROM_HELP_2)) {
            return new String[0];
        }

        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_INFORMATION_SCHEMA_2)) {
            return new String[0];
        }

        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_MYSQL)) {
            return new String[0];
        }

        for (String each : NO_PARAMETER_FUNCTIONS) {
            if (sqlTrimUpper.startsWith(each)) {
                return new String[0];
            }
        }

        throw new BudoJdbcDriverNotSupportedException("#120 sql not supported, sql=" + sql);
    }

    static String parseFunctionName_1(String sql, String functionSql) {
        int beginIndex = 0;
        int endIndex = functionSql.indexOf('(');

        if (endIndex > 0) { // 有 function 的方式
            String functionName = functionSql.substring(beginIndex, endIndex);
            return functionName.trim().toUpperCase();
        }

        throw new BudoJdbcDriverNotSupportedException("#64 sql not supported, sql=" + sql);
    }

    /**
     * 解析无function的特定语句
     */
    static String parseFunctionName_2(String sql) {
        String sqlTrim = sql.replaceAll(BLANK_REGEX, "").replaceAll(" +", "").trim();
        String sqlTrimUpper = sqlTrim.toUpperCase();

        if (sqlTrimUpper.startsWith(SHOW_VARIABLES_2)) {
            return SHOW_VARIABLES.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_DATABASES_2)) {
            return SHOW_DATABASES.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_FULL_TABLES_2)) {
            return SHOW_FULL_TABLES.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_TABLE_STATUS_2)) {
            return SHOW_TABLE_STATUS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_PROCEDURE_STATUS_2)) {
            return SHOW_PROCEDURE_STATUS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_FULL_COLUMNS_FROM_2)) {
            return SHOW_FULL_COLUMNS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_ENGINES_2)) {
            return SHOW_ENGINES.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_CREATE_TABLE_2)) {
            return SHOW_CREATE_TABLE.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_CREATE_FUNCTION_2)) {
            return SHOW_CREATE_FUNCTION.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_CHARACTER_SET_2)) {
            return SHOW_CHARACTER_SET.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_COLLATION_2)) {
            return SHOW_COLLATION.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_COLUMNS_FROM_2)) {
            return SHOW_COLUMNS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_STATUS_2)) {
            return SHOW_STATUS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT_AT_AT_2)) {
            return SELECT_AT_AT.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SET_NAMES_2)) {
            return SET_NAMES.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(CREATE_TABLE_2)) {
            return CREATE_TABLE.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(DROP_TABLE_2)) {
            return DROP_TABLE.class.getSimpleName();
        }

        if (sqlTrimUpper.contains(SET_VALUE) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是update-value特例语句
            return SET.class.getSimpleName();
        }

        if (sqlTrimUpper.contains(SET_EXPIRE) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是update-expire特例语句
            return EXPIRE.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT_KEY_FROM) && sqlTrimUpper.contains(WHERE_KEY_LIKE)) { // 是select-key特例语句
            return KEYS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT_VALUE_FROM) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是select-key特例语句
            return GET.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(DELETE_FROM) && sqlTrimUpper.contains(WHERE_KEY_EQ)) { // 是delete-key特例语句
            return DEL.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_INFORMATION_SCHEMA_2)) {
            return SELECT_INFORMATION_SCHEMA.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_MYSQL)) {
            return SELECT_MYSQL.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SHOW_FUNCTION_STATUS_2)) {
            return SHOW_FUNCTION_STATUS.class.getSimpleName();
        }

        if (sqlTrimUpper.startsWith(SELECT_FROM_HELP_1) || sqlTrimUpper.startsWith(SELECT_FROM_HELP_2)) {
            return SELECT_HELP.class.getSimpleName();
        }

        // SELECT aaa FROM hash.session WHERE key=?
        if (sqlTrimUpper.startsWith(SELECT) && sqlTrimUpper.contains(FROM_HASH) && sqlTrimUpper.contains(WHERE_KEY_EQ)) {
            return HGET.class.getSimpleName();
        }

        // UPDATE hash.session SET
        // UPDATEHASH.SESSIONSETFIELD_1=NULL,FIELD_2=NULLWHEREKEY=?
        if (sqlTrimUpper.startsWith(UPDATE_HASH) && sqlTrimUpper.contains(SET) && sqlTrimUpper.contains(EQ_NULL) && sqlTrimUpper.contains(WHERE_KEY_EQ)) {
            return HDEL.class.getSimpleName();
        }

        return null;
    }

    static String parseParameter(String value) {
        if (null == value) {
            return null;
        }

        String valueTrim = value.trim();
        if (valueTrim.isEmpty() || "?".equals(valueTrim)) {
            return valueTrim; // 空值和问号占位符，直接返回
        }
        int trimLength = valueTrim.length();

        // 去掉字符串首尾的单引号
        int a1 = 0;
        int b1 = Integer.MAX_VALUE;
        if (valueTrim.charAt(0) == '\'') {
            a1 = 1;
        }

        if (valueTrim.charAt(trimLength - 1) == '\'') {
            b1 = trimLength - 1;
        }

        if (a1 > 0 || b1 < trimLength) {
            return valueTrim.substring(a1, b1); // 返回去掉引号的值
        }

        // 去掉字符串首尾的双引号
        int a2 = 0;
        int b2 = Integer.MAX_VALUE;
        if (valueTrim.charAt(0) == '\"') {
            a2 = 1;
        }

        if (valueTrim.charAt(trimLength - 1) == '\"') {
            b2 = trimLength - 1;
        }

        if (a2 > 0 || b2 < trimLength) {
            return valueTrim.substring(a2, b2); // 返回去掉引号的值
        }

        return valueTrim; // 返回本来的值
    }
}
